package com.cpr.core.concurrency.waitAndNotify;

import java.util.HashSet;
import java.util.Set;

/**
 * @author Chen Panrui
 * created at 2022/4/16 17:07
 * 假设：一个party里面只能有3个人进入,每个线程代表一个人进入或者退出这个party
 *
 * 因为 synchronized 有可能让所有的对象都成为监视器关联的对象，所以Object类里面都预设置了wait和notify方法
 * 
 * 假设线程t对m对象调用了wait()方法,数字n表示t对m进行的加锁的次数
 * 如果n是0，抛异常IllegalMonitorStateException
 * 在m中的wait set中存在一个线程u,若调用u.interrupt()会抛异常InterruptedException,导致线程u不能在接收其他线程的notify
 *
 * while(!this.done)
 *  Thread.sleep(1000);
 * 上述代码中，假设this.done是non-volatile修饰的，那么编译器只会读取this.done的值一次，并缓存该值在以后while的循环判断里面，这意味
 * 着这个循环不会被终结，就算有其他线程来修改this.done的值
 */
public class Party {

    private final Object door = new Object();

    private static final int MAX_PERSON = 3;
    private int currentPerson = 0;
    private static final Set<String> CURRENT_USER = new HashSet<>();

    /**
     * 加入派对
     * @throws InterruptedException 异常
     */
    public void enterParty() throws InterruptedException {
        synchronized (door){
            String who = Thread.currentThread().getName();
            while (true){
                if(CURRENT_USER.contains(who)){
                    System.out.println(who + "已经在party中了...");
                    break;
                }
                if(currentPerson+1<=MAX_PERSON){
                    int process = 1;
                    System.out.print(who + "进入party...这需要花费" + process + "秒");
                    Thread.sleep(process * 1000L);
                    System.out.println("--进入成功...");
                    currentPerson++;
                    CURRENT_USER.add(who);
                    break;
                } else {
                    System.out.println(who + "暂时不能进入party...人数已满");
                    door.wait();
                }
            }
        }
    }

    /**
     * 离开派对
     */
    public void exitParty(){
        synchronized (door){
            String who = Thread.currentThread().getName();
            if(CURRENT_USER.remove(who)){
                System.out.println(who + "成功退出party...");
                currentPerson--;
                door.notifyAll();
            } else {
                System.out.println(who + "没有进入party,不能退出!");
            }
        }
    }

    public void info(){
        synchronized (door){
            System.out.println(CURRENT_USER);
        }
    }
}
